SUCCESS = 0
FAILED	= 1

USEMMX	= 1
USESSE	= 2
USESSE2 = 3
USESSE3 = 4
USESSE4 = 5

TYPEDEF_X64_EQU REG_A, rax, eax
TYPEDEF_X64_EQU REG_B, rbx, ebx
TYPEDEF_X64_EQU REG_C, rcx, ecx
TYPEDEF_X64_EQU REG_D, rdx, edx
TYPEDEF_X64_EQU REG_BP, rbp, ebp
TYPEDEF_X64_EQU REG_SP, rsp, esp
TYPEDEF_X64_EQU REG_SI, rsi, esi
TYPEDEF_X64_EQU REG_DI, rdi, edi
TYPEDEF_X64_EQU ADDR_T, qword, dword

macro STRUCTARRAY name, structname, [args] {
    common
	    name:
    forward
      structname args
    common
      sizeof.#name = $ - name
      countof.#name = ($ - name)/ sizeof.#structname
}

;nodefine SizeOfKernel, 10000

macro return retval {
    if ~ retval eq
        mov REG_A, retval
    else if retval eq 0
        xor REG_A, REG_A
    end if
        ret
}

macro m2m arg1*,arg2* {
    push arg2
    pop arg1
}

macro STARTTIMER qvara {
      cpuid			     ;force all previous instructions to complete
      rdtsc			     ;read time stamp counter
      mov     dword [qvara + 4], edx ;store hi-qword in GLOBAL variable
      mov     dword [qvara], eax     ;store lo-qword in GLOBAL variable
}

macro STOPTIMER qvara, qvarb {
      cpuid			     ;force all timed instructions to complete
      rdtsc			     ;read time stamp counter
      mov     dword [qvarb + 4], edx ;store hi-qword in second GLOBAL variable
      mov     dword [qvarb], eax     ;store lo-qword in second GLOBAL variable
      fild    [qvarb]		     ;load 64-bit current value into FPU
      fild    [qvara]		     ;load and subtract 64-bit start value into FPU
      fsubp			     ;subtract 64-bit start value
      fstp    [qvara]		     ;store in first GLOBAL variable
}

macro NRET {
      db $c3
}

macro PUSHWIN {
      push REG_B
      push REG_SI
      push REG_DI
      push REG_BP
}

macro POPWIN {
      pop REG_BP
      pop REG_DI
      pop REG_SI
      pop REG_B
}

macro fldq dfloat {
     local ..mynumber, ..here
     fld [..mynumber]
     jmp ..here
     align 8
     ..mynumber dq dfloat
  ..here:
}

macro fldd dfloat {
     local ..mynumber, ..here
     fld [..mynumber]
     jmp ..here
     align 8
     ..mynumber dd dfloat
     align 8
  ..here:
}

macro fildd integer {
     local ..mynumber, ..here
     jmp ..here
     align 8
     ..mynumber dd integer
     align 8
..here:
     fild [..mynumber]
}

macro fildq integer {
     local ..mynumber, ..here
     jmp ..here
     align 8
     ..mynumber dq integer
..here:
     fild [..mynumber]
}


;enum RET_OK, RET_ERROR After this RET_OK = 0 and RET_ERROR = 1
macro ENUM [rets] {
common
   count = 0
forward
   rets = count
   count = count + 1
}

;align with a specific byte value
macro FALIGN value, fill {
  if fill eq
   align value
  else
   local ..size
   virtual
     @@: align value
    ..size = $-@b
  end virtual
   times ..size db fill
  end if
}

;array of pointers to strings
macro STRINGA_ARRAY name, [string] {
    common label name ADDR_T
    forward local label
    void label
    forward label db string,0
}

macro STRINGW_ARRAY name, [string] {
    common label name ADDR_T
    forward local label
    void label
    forward label du string,0
}

macro STRING_ARRAY Name, [string]
{ common
	match =TRUE,UNICODE \{ STRINGW_ARRAY Name, string \}
	match =FALSE,UNICODE \{ STRINGA_ARRAY Name, string \}
}

macro __digit num {
   if num < 10
    display '0'+num
   else
    display 'A'+num-10
   end if
}

;DISPLAY "Offset: ",<$,16>,13,10
macro __display arg1, arg2 {
   if arg2 eq
    display arg1
   else
    local ..tmp
    ..tmp = arg1
    virtual at 0
     repeat 32
      if ..tmp > 0
       db ..tmp mod arg2
       ..tmp = ..tmp / arg2
      end if
     end repeat
     repeat $
      load ..tmp byte from $-%
      __digit ..tmp
     end repeat
     if $ = 0
      display '0'
     end if
    end virtual
   end if
}

macro DISPLAY [arg] { __display arg }

macro MAKE_HRESULT name, sev, fac, code {  name = (sev shl 31) or (fac shl 16) or (code)  }

macro RGB555 r, g, b {	VALUE = ((r shr 3) shl 11) + ((g shr 3) shl 5) + (b shr 3)  }
macro RGB565 r, g, b {	VALUE = ((r shr 3) shl 11) + ((g shr 2) shl 5) + (b shr 3)  }
macro VRGB888 colorequ, r, g, b {   colorequ = (r shl 16) + (g shl 8) + b   }
macro RGB888 r, g, b {	VALUE = (r shl 16) + (g shl 8) + b  }
macro RGBA888 a, r, g, b {  VALUE = (a shl 24) + (r shl 16) + (g shl 8) + b  }

macro CodeColor byteRed, byteGreen, byteBlue
{
    xor eax, eax
    mov ah, byteBlue
    mov al, byteGreen
    shl eax,8
    mov al, byteRed
}

macro CodeTextA Name, quoted_text
{
	jmp @f
	Name:  db quoted_text,0
@@:
}

macro CodeTextW Name, quoted_text
{
	jmp @f
	Name:  du quoted_text,0
@@:
}

macro CodeText Name, quoted_text
{
	match =TRUE,UNICODE \{ CodeTextW Name, quoted_text \}
	match =FALSE,UNICODE \{ CodeTextA Name, quoted_text \}
}

macro CodeDate lpszStrPtr
{
	push rsi
	push rdi
	invoke GlobalAlloc, GPTR, MAX_PATH
	mov rsi, rax
	invoke GetSystemTime, rsi
	mov rdi, rsi
	add rdi, 64
	invoke GetDateFormat, LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, rsi, NULL, rdi, MAX_PATH - 65
	invoke lstrcpy, lpszStrPtr, rdi
	invoke GlobalFree, rsi
	pop rdi
	pop rsi
}

macro CodeNow lpszStrPtr
{
	push rsi
	push rdi
	invoke GlobalAlloc, GPTR, MAX_PATH
	mov rsi, rax
	invoke GetSystemTime, rsi
	mov rdi, rsi
	add rdi, 64
	invoke GetDateFormat, LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, rsi, NULL, edi, MAX_PATH - 65
	invoke lstrcpy, lpszStrPtr, rdi
	invoke lstrcat, lpszStrPtr, ' - '
	invoke GetTimeFormat, LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, rsi, NULL, edi, MAX_PATH - 65
	invoke lstrcat, lpszStrPtr, rdi
	invoke GlobalFree, rsi
	pop rdi
	pop rsi
}

macro CodeTime lpszStrPtr
{
	push rsi
	push rdi
	invoke GlobalAlloc, GPTR, MAX_PATH
	mov rsi, rax
	invoke GetSystemTime, rsi
	mov rdi, rsi
	add rdi, 64
	invoke GetTimeFormat, LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, rsi, NULL, rdi, MAX_PATH - 65
	invoke lstrcpy, lpszStrPtr, rdi
	invoke GlobalFree, rsi
	pop rdi
	pop rsi
}